#include "incrustation.hh"

ApplyIncrustation::ApplyIncrustation(IplImage* input1,
				     IplImage* input2,
				     unsigned r,
				     unsigned g,
				     unsigned b,
				     unsigned error)
{
  this->input1 = input1;
  this->input2 = input2;

  this->r = r;
  this->g = g;
  this->b = b;

  this->error = error;

  output = cvCreateImage (cvSize (input1->width, input1->height),
			  IPL_DEPTH_8U, 3);
}

void ApplyIncrustation::operator()(const tbb::blocked_range2d<int>& r) const
{
  for (int i = r.rows().begin(); i!= r.rows().end(); ++i)
    for (int j = r.cols().begin(); j!= r.cols().end(); ++j)
      {
	CvScalar v1 = cvGet2D (input1, i, j);
	
	if ((abs( (int) v1.val[0] - (int) this->r ) < error)
	    && (abs( (int) v1.val[1] - (int) this->g ) < error)
	    && (abs( (int) v1.val[2] - (int) this->b ) < error))
	  {
	    CvScalar v2 = cvGet2D (input2, i, j);
	    cvSet2D (output, i, j, v2);
	  }
	else
	  {
	    cvSet2D (output, i, j, v1);
	  }
      }
}

IplImage* ApplyIncrustation::getOutput()
{
  return output;
}

IplImage*
incrustation(IplImage* input1,
	     IplImage* input2,
	     unsigned r,
	     unsigned g,
	     unsigned b,
	     unsigned error)
{
  ApplyIncrustation app(input1, input2, r, g, b, error);

  tbb::parallel_for(tbb::blocked_range2d<int>(0,input1->height, 0, input2->width),
                    app, tbb::auto_partitioner());

  return app.getOutput();
}
